package com.binarycat.dynamiclimit.limiter.policy;

import java.util.concurrent.atomic.AtomicBoolean;

import com.binarycat.dynamiclimit.bean.DynamicLimiterConfig;
import com.binarycat.dynamiclimit.bean.LimitPolicyEnum;
import com.binarycat.dynamiclimit.util.LimitRateLogUtils;
import com.binarycat.util.jvm.SystemInfoUtils;
import com.codahale.metrics.Meter;
import com.google.common.util.concurrent.RateLimiter;

/**
 * 依据CPU负载的限流策略
 * 
 * @author jjb
 * @date 2018/08/06
 */
public class CpuLoadLimitPolicy extends AbstractSystemLevelLimitPolicy {

    @Override
    protected boolean startLimit() {
        double jvmProcessCpuLoad = SystemInfoUtils.getJvmProcessCpuLoad();
        metricConditionValueTem = jvmProcessCpuLoad;

        DynamicLimiterConfig config = dynamicLimiterManager.getDynamicLimiterConfig();
        // cpu负载超过阀值
        if (jvmProcessCpuLoad > config.getCpuLimitRateThreshold()) {

            filterLimitTargetMethod();

            boolean limitStatus = limitTargetMethodMappingLimitData.getLimitRateStatus().get();

            double oneMinuteRate = ((Meter)limitTargetMetric).getOneMinuteRate();
            metricQpsValueTem = oneMinuteRate;
            // 开启限流
            if (!limitStatus && oneMinuteRate > config.getQpsProtectionValue()) {
                limitTargetMethodMappingLimitData.getRateLimiter().setRate(oneMinuteRate);
                limitTargetMethodMappingLimitData.getLimitRateStatus().set(true);
                LimitRateLogUtils.log("CPU负载的限流策略开始限流");
            }
            return true;
        }
        // 该策略从来没有进行过限流
        if (limitTargetMethodMappingLimitData == null) {
            return false;
        }

        return limitTargetMethodMappingLimitData.getLimitRateStatus().get();
    }

    @Override
    protected boolean reduceLimitThreshold() {

        DynamicLimiterConfig dynamicLimiterConfig = dynamicLimiterManager.getDynamicLimiterConfig();

        // 未开始限流
        if (!limitTargetMethodMappingLimitData.getLimitRateStatus().get()) {
            return false;
        }
        // cpu负载未超过阀值
        if (metricConditionValueTem <= dynamicLimiterConfig.getCpuLimitRateThreshold()) {
            return false;
        }
        RateLimiter rateLimiter = limitTargetMethodMappingLimitData.getRateLimiter();
        double qpsChangeRate = dynamicLimiterConfig.getQpsChangeRate();
        int qpsProtectionValue = dynamicLimiterConfig.getQpsProtectionValue();
        double rate = rateLimiter.getRate();
        double limitRateReduceValueByCpuLoad = rate * qpsChangeRate;
        double qps = rate - limitRateReduceValueByCpuLoad;
        if (qps < qpsProtectionValue) {
            qps = qpsProtectionValue;
        }
        LimitRateLogUtils.log("cpu限流策略开始降低限流阀值,降低了" + Math.round(rate - qps));

        rateLimiter.setRate(Math.round(qps));

        return true;

    }

    @Override
    protected boolean endLimit() {
        double jvmProcessCpuLoad = metricConditionValueTem;
        DynamicLimiterConfig config = dynamicLimiterManager.getDynamicLimiterConfig();
        double oneMinuteRate = metricQpsValueTem;
        RateLimiter rateLimiter = limitTargetMethodMappingLimitData.getRateLimiter();
        AtomicBoolean limitRateStatus = limitTargetMethodMappingLimitData.getLimitRateStatus();
        if (!limitRateStatus.get()) {
            return true;
        }
        // cpu负载低于低于阀值的一半,或者当前限流器的速率高于实际的度量的速率的两倍则关闭限流
        if (jvmProcessCpuLoad <= (config.getCpuLimitRateThreshold() * RATIO)
            || rateLimiter.getRate() >= (oneMinuteRate * 2)) {
            limitRateStatus.set(false);
            LimitRateLogUtils.log("cpu限流策略关闭限流");
            return true;
        }
        return false;

    }

    @Override
    protected boolean increaseLimitThreshold() {
        DynamicLimiterConfig dynamicLimiterConfig = dynamicLimiterManager.getDynamicLimiterConfig();
        // 未开始限流
        if (!limitTargetMethodMappingLimitData.getLimitRateStatus().get()) {
            return false;
        }
        // cpu负载超过阀值
        if (metricConditionValueTem >= dynamicLimiterConfig.getCpuLimitRateThreshold()) {
            return false;
        }

        RateLimiter rateLimiter = limitTargetMethodMappingLimitData.getRateLimiter();
        double qpsChangeRate = dynamicLimiterManager.getDynamicLimiterConfig().getQpsChangeRate();
        double limitRateReduceValueByCpuLoad = rateLimiter.getRate() * qpsChangeRate;
        rateLimiter.setRate(Math.round(rateLimiter.getRate() + limitRateReduceValueByCpuLoad));
        LimitRateLogUtils.log("cpu限流策略开始升高限流阀值,升高了" + Math.round(limitRateReduceValueByCpuLoad));
        return true;

    }

}
